package map;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

import logic.common.team.Fraction;
import logic.nodes.lod.blocks.Block;
import logic.nodes.nodeSettings.upgrades.UpgradableSettings;
import map.asteroids.AsteroidField;
import map.asteroids.AsteroidFieldProperties;
import map.infos.MapDescription;
import map.infos.MapInfos;
import map.infos.TeamInfos;
import map.spawnStation.SpawnPointProperties;
import map.spawnStation.SpawnStation;
import map.spawnStation.SpawnStationProperties;

import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.scene.Node;

import fileHandling.ModelImporter;
import fileHandling.MapLoader;
import fileHandling.SettingsLoader;
import gameStates.absGamesStates.AbsIngameState;

public class Map {
		
	private final String SPAWNSTATION_FILE = "data/models/spawnStation/properties.xml";
	
	protected Stardust starDust;
	protected List<AsteroidFieldProperties> asteroidFieldProperties;
	protected List<AsteroidField> asteroidFields;
	protected List<AsteroidField> unfinishedFields;
	
	protected Block rootBlock;
	
	protected AtomicInteger activeThreads;
	
	protected List<SpectatorPoint> camSpawns;
	
	protected Random r;
		
	protected String path;
	
	private TeamInfos teamAInfos, teamBInfos;
	
	private List<SpawnStation> spawnStations;
	private List<SpawnPointProperties> spawnProps;
	
	private MapInfos mapInfos;
	
	private MapDescription description;
		
	public Map(MapInfos matchInfos, TeamInfos teamAInfos, TeamInfos teamBInfos, List<SpawnPointProperties> spawnProps, 
			List<SpectatorPoint> camSpawns, List<AsteroidFieldProperties> asteroidFieldProps, MapDescription description, String path) {
		this.camSpawns = camSpawns;
		this.asteroidFieldProperties = asteroidFieldProps;
		this.path = path;
		this.teamAInfos = teamAInfos;
		this.teamBInfos = teamBInfos;
		this.mapInfos = matchInfos;
		this.spawnProps = spawnProps;
		this.description = description;
		
		r = new Random();
		
		unfinishedFields = new ArrayList<AsteroidField>();
		spawnStations = new ArrayList<SpawnStation>();
	}
	
	public void generateSpawns(AbsIngameState ingameState) {
		for(SpawnPointProperties props : spawnProps) {
			UpgradableSettings settings = SettingsLoader.loadUpgradableSettings(SPAWNSTATION_FILE);
			SpawnStationProperties spawnStationProps = new SpawnStationProperties(settings);
			
			String modelPath = settings.getModelPath();
			Node spawnModel = ModelImporter.getModel(modelPath);
			if(spawnModel == null) return;
			
			SpawnStation station = new SpawnStation(modelPath, "SpawnStation", spawnModel, props, 
					spawnStationProps, ingameState);
			spawnStations.add(station);
		}
	}
	
	public List<SpawnStation> getSpawnStations() { return spawnStations; }
	
	public Fraction getFractionA() { return mapInfos.getFractionA(); }
	
	public Fraction getFractionB() { return mapInfos.getFractionB(); }
	
	public int getTime() { return mapInfos.getTime(); }
	
	public MapInfos getMatchInfos() { return mapInfos; }
	
	public MapDescription getMapDescription() { return description; }
	
	public TeamInfos getTeamInfos(Fraction fraction) {
		if(fraction == getFractionA()) return teamAInfos;
		return teamBInfos;
	}
	
	public void initStarDust(Camera cam) { starDust = new Stardust(400, 1000, cam); }
	
	public void initBlocks(AbsIngameState ingameState) {
		rootBlock = new BlocksCreator().getRootBlock(getDimension(), ingameState);
		ingameState.setRootBlock(rootBlock);
	}
	
	public void initAsteroidFields() {
		asteroidFields = new ArrayList<AsteroidField>();
		
		for(AsteroidFieldProperties fieldProps : asteroidFieldProperties) {
			AsteroidField field = new AsteroidField(fieldProps, rootBlock);
			asteroidFields.add(field);
			unfinishedFields.add(field);
		}
	}
	
	public void fillAsteroidFields(int percentage, boolean last) {
		if(unfinishedFields.isEmpty()) return;
		List<AsteroidField> finishedFields = new ArrayList<AsteroidField>();
		if(last) percentage = 100;
		
		for(int i = 0; i < unfinishedFields.size(); i++) {
			if(unfinishedFields.get(i).createAsteroids(percentage)) 
				finishedFields.add(unfinishedFields.get(i));
		}
		unfinishedFields.removeAll(finishedFields);
	}
	
	public List<SpawnPointProperties> getSpawnProps() { return spawnProps; }
	
	public void setupSpectatePoint(Camera cam) {
		SpectatorPoint point = camSpawns.get(r.nextInt(camSpawns.size()));
		point.setupCam(cam);
		
		float dim = getDimension();
		Vector3f center = new Vector3f(dim / 2f, 0f, dim / 2f);
		cam.lookAt(center, Vector3f.UNIT_Y);
		cam.update();
	}
	
	public String getMapName() { return mapInfos.getMapName(); }
	
	public int getDimension() { return mapInfos.getDimension(); }
	
	public SpaceBackground getBackground() { return mapInfos.getSpaceBackground(); }
	
	public Stardust getStardust() { return starDust; }
	
	public List<AsteroidField> getAsteroidFields() { return asteroidFields; }
		
	public String getPath() { return path; }
	
	public String getPreviewPath() { return MapLoader.MAPS_PATH + getPath() + "/preview.png"; }
	
	public String getMapPath() { return MapLoader.MAPS_PATH + getPath() + "/map.png"; }
	
	public Block getRootBlock() { return rootBlock; }
}